package obj

import (
	"testing"
)

func TestStringValue(t *testing.T) {
	str := &StringValue{Value: "hello world"}
	
	expected := `"hello world"`
	if str.String() != expected {
		t.Errorf("expected %s, got %s", expected, str.String())
	}
	
	if str.Type() != "string" {
		t.Errorf("expected type 'string', got '%s'", str.Type())
	}
}

func TestSymbolValue(t *testing.T) {
	sym := &SymbolValue{Name: "test-symbol"}
	
	expected := "test-symbol"
	if sym.String() != expected {
		t.Errorf("expected %s, got %s", expected, sym.String())
	}
	
	if sym.Type() != "symbol" {
		t.Errorf("expected type 'symbol', got '%s'", sym.Type())
	}
}

func TestNilValue(t *testing.T) {
	nilVal := &NilValue{}
	
	expected := "()"
	if nilVal.String() != expected {
		t.Errorf("expected %s, got %s", expected, nilVal.String())
	}
	
	if nilVal.Type() != "nil" {
		t.Errorf("expected type 'nil', got '%s'", nilVal.Type())
	}
}

func TestEnvironment(t *testing.T) {
	env := NewEnvironment()
	
	// Test setting and getting values
	strVal := &StringValue{Value: "test"}
	env.Set("test-var", strVal)
	
	retrieved, ok := env.Get("test-var")
	if !ok {
		t.Fatal("expected to find test-var in environment")
	}
	
	if retrieved != strVal {
		t.Error("retrieved value does not match set value")
	}
	
	// Test getting non-existent value
	_, ok = env.Get("non-existent")
	if ok {
		t.Error("expected not to find non-existent variable")
	}
}

func TestNestedEnvironment(t *testing.T) {
	// Create parent environment
	parent := NewEnvironment()
	parent.Set("parent-var", &StringValue{Value: "parent-value"})
	
	// Create child environment
	child := NewEnclosedEnvironment(parent)
	child.Set("child-var", &StringValue{Value: "child-value"})
	
	// Test accessing parent variable from child
	parentVal, ok := child.Get("parent-var")
	if !ok {
		t.Fatal("expected to find parent-var in child environment")
	}
	
	if parentVal.String() != `"parent-value"` {
		t.Errorf("expected 'parent-value', got %s", parentVal.String())
	}
	
	// Test accessing child variable from parent (should fail)
	_, ok = parent.Get("child-var")
	if ok {
		t.Error("expected not to find child-var in parent environment")
	}
}

func TestEnvironmentString(t *testing.T) {
	env := NewEnvironment()
	env.Set("var1", &StringValue{Value: "value1"})
	env.Set("var2", &SymbolValue{Name: "symbol2"})
	
	str := env.String()
	if !contains(str, "var1:") || !contains(str, "value1") {
		t.Error("expected string representation to contain var1 and value1")
	}
	if !contains(str, "var2:") || !contains(str, "symbol2") {
		t.Error("expected string representation to contain var2 and symbol2")
	}
}

func contains(s, substr string) bool {
	return len(s) >= len(substr) && (s == substr || len(s) > 0 && containsHelper(s, substr))
}

func containsHelper(s, substr string) bool {
	for i := 0; i <= len(s)-len(substr); i++ {
		if s[i:i+len(substr)] == substr {
			return true
		}
	}
	return false
}